#pragma once

#include "3rd_part\xml\tinyxml.h"
#include "AxisAlignedBox.h"

//external functions
extern TCHAR *GetString(int id);
extern HINSTANCE hInstance;

//Version number of exporter * 100
const int MFX_EXPORT_VERSION = 100;

//Global class id.
#if defined _DEBUG
#define EXP_CLASS_ID	Class_ID(0x3b4846fb, 0x68ab3b30)
#else
#define EXP_CLASS_ID	Class_ID(0x681e6311, 0x31407d11)
#endif

//Config fileName
const std::string CFGFilename("visualexporter.cfg");

typedef std::vector< INode* > INodeVector;

class MaterialList
{
private:

	std::vector< Mtl* > materials_;

public:
	void addMaterial( Mtl * mtl )
	{
		if( mtl )
		{
			std::vector< Mtl* >::iterator it = std::find( materials_.begin(), materials_.end(), mtl );
			if( it == materials_.end() )
			{
				materials_.push_back( mtl );
			}
		}
	}

	Mtl *getMaterial( int index ) const
	{
		return materials_[ index ];
	}

	int getNMaterials( void ) const
	{
		return materials_.size();
	}


};

typedef struct
{
	INode *node;
	std::vector< int > vertexIndices;
} Bone;

class BoneList
{
private:

	std::vector< Bone > bones_;

public:

	/*
	 * Find a bone by node reference
	 */
	Bone *findBone( INode *node )
	{
		for( int i = 0; i < bones_.size(); i++ )
		{
			if( node == bones_[ i ].node )
				return &bones_[ i ];
		}
		return NULL;
	}

	/*
	 * Add a bone to the bone list
	 * If there is a bone attached to the node already, the index gets added to the
	 * vertexIndex list of that bone.
	 */
	void addBone( INode *node, int index )
	{
		Bone *bone = findBone( node );
		if( bone )
		{
			bone->vertexIndices.push_back( index );
		}
		else
		{
			Bone bn;
			bn.node = node;
			bn.vertexIndices.push_back( index );
			bones_.push_back( bn );
		}
	}

	Bone *getBone( int index )
	{
		return &bones_[ index ];
	}

	int getNBones( void ) const
	{
		return bones_.size();
	}
};

typedef struct 
{
	Mtl *mtl_;
	std::vector< std::string > children_;

} MultiSubMaterial;

//struct ExportSettings;

class ExMesh;
class ExPortal;
class ExNode;
class ExHullMesh;
/*
this exporter is used to export .visual objects
the format is defined as below:

<visualname.visual>
	<node> hierachy </node>
	<model> visual.model </model>
	<boundary>
		<portal> portalName </portal>
	</boundary>
	<bounding_box> xxx </bounding_box>
</visualname.visual>

*/

class Exporter : public SceneExport
{
public:
	typedef std::map<std::string, int>	BoneCountMap;
	typedef BoneCountMap::iterator		BoneCountMapIt;
	
	Exporter();
	virtual ~Exporter();

	int				ExtCount();					// Number of extensions supported
	const TCHAR *	Ext(int n);					// Extension #n
	const TCHAR *	LongDesc();					// Long ASCII description
	const TCHAR *	ShortDesc();				// Short ASCII description
	const TCHAR *	AuthorName();				// ASCII Author name
	const TCHAR *	CopyrightMessage();			// ASCII Copyright message
	const TCHAR *	OtherMessage1();			// Other message #1
	const TCHAR *	OtherMessage2();			// Other message #2
	unsigned int	Version();					// Version number * 100
	void			ShowAbout(HWND hWnd);		// Show DLL's "About..." box
	int				DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options = 0);	// Export file
	BOOL			SupportsOptions( int ext, DWORD options ) { return options == SCENE_EXPORT_SELECTED; }

	//static Modifier* findPhysiqueModifier( INode* node );
	//static Modifier* findMorphModifier( INode* node );
	//static TriObject* getTriObject( INode *node, TimeValue t, bool &needDelete );
	//static class IEditNormalsMod* findEditNormalsMod( INode* node );
	//static class Modifier* findSkinMod( INode* node );

private:
	void _PreProcess( ExNode* pParent );
	/*
	 * Export functions
	 */
	//bool exportMaterial( StdMat *mat, bool overrideMaterialName = false, const std::string &overrideName = "" );
	
	//void getBoneCounts( BoneCountMap& boneCountMap );

	void _ExtractMeshes( bool snapVertices, TiXmlNode* pVisualSection );
	void _ExtractPortals( bool snapVertices );

	void _ExportHierachy( TiXmlNode* pVisualSection );

	void _GenerateHull( TiXmlNode* pHullSection, const Common::AxisAlignedBox& bb );
	void _ExportHull( TiXmlNode* pHullSection );

	/*
	 * Helper functions
	 */
	//std::string getCfgFilename( void );
	//MultiSubMaterial *findMultiSubMaterial( Mtl *mtl );
	bool _IsShell( INode *node );

	void _UpdateBoundingBox( Common::AxisAlignedBox& rBoundingbox );
	void _ExportPortalsToBoundaries( TiXmlNode* pHullSection );

	void _ResetAll( void );

private:

	Interface*		ip_; //max Interface

	//MaterialList	materials_; //Our list of materials
	
	unsigned int	m_uNodeCount; //Number of nodes
	unsigned int	m_uAnimNodeCount; //Number of animated nodes

	//ExportSettings&	m_Settings;

	INodeVector m_PortalNodes;
	INodeVector m_MeshNodes;

	std::vector<ExMesh*> m_VisualMeshes;
	std::vector<ExPortal*> m_VisualPortals;
	std::vector<ExMesh*> m_HullMeshes;

	ExNode* m_pRoot;
	TimeValue m_iStaticFrame;

	std::string m_strFileName;
	std::string m_strFilePath;

	Exporter(const Exporter&);
	Exporter& operator=(const Exporter&);
};